package com.piesat.quake.business.device.bis;

import com.piesat.quake.business.device.model.DeviceStatus;
import com.piesat.quake.business.station.model.StationInfo;

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 设备缓存
 *
 * @author Gersy
 * @date 2023/3/3
 * @since 1.0
 */
@Component
public class DeviceCache {
    /**
     * 超时时间，单位为秒
     */
    private static final int TIME_OUT = 10;
    private static final ConcurrentHashMap<String, StationInfo> MAP = new ConcurrentHashMap<>();
    private static final Set<ConnectionEvent> EVENTS = new HashSet<>();

    public void initCache(List<StationInfo> list) {
        long dataTimestamp = System.currentTimeMillis();
        for (StationInfo stationInfo : list) {
            stationInfo.setDataTimestamp(dataTimestamp);
            put(stationInfo.getId(), stationInfo);
        }
    }

    public List<StationInfo> getByRegionCode(String regionCode) {
        return MAP.values()
                .stream()
                .filter(stationInfo -> stationInfo.getRegionCode().equals(regionCode))
                .collect(Collectors.toList());
    }

    public StationInfo get(String id){
        return MAP.get(id);
    }

    public void put(String clientId, StationInfo stationInfo) {
        MAP.put(clientId, stationInfo);
    }

    public void update(String clientId, DeviceStatus deviceStatus) {
        StationInfo stationInfo = MAP.get(clientId);
        if (stationInfo == null) {
            return;
        }
        stationInfo.setDataTimestamp(deviceStatus.getTimestamp());
        if (!stationInfo.getOnline()) {
            stationInfo.setOnline(true);
            onConnected(stationInfo);
        }
        stationInfo.setTemperature(deviceStatus.getTemperature() / 10f);
    }

    /**
     * 定时检测设备的在线状态
     */
    @Scheduled(cron = "*/15 * * * * ?")
    public void checkTimeout() {
        long currentTimeMillis = System.currentTimeMillis();
        MAP.values()
                .forEach(stationInfo -> {
                    if (!stationInfo.getOnline()){
                        return;
                    }
                    Long dataTimestamp = stationInfo.getDataTimestamp();
                    if (dataTimestamp != null) {
                        if (currentTimeMillis - dataTimestamp > TIME_OUT) {
                            stationInfo.setOnline(false);
                            onDisconnected(stationInfo.getId());
                        }
                    }
                });
    }

    public void onDisconnected(String id){
        for (ConnectionEvent event : EVENTS) {
            event.onDisconnected(id);
        }
    }

    public void onConnected(StationInfo stationInfo){
        for (ConnectionEvent event : EVENTS) {
            event.onConnected(stationInfo);
        }
    }

    public void remove(String id) {
        MAP.remove(id);
    }

    public void registerEvent(ConnectionEvent event) {
        EVENTS.add(event);
    }

    public void unregisterEvent(ConnectionEvent event) {
        EVENTS.remove(event);
    }

    public static interface ConnectionEvent {
        void onConnected(StationInfo stationInfo);

        void onDisconnected(String id);
    }
}
